package com.h5ve.data.config;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import lombok.extern.slf4j.Slf4j;

/**
 * @author yong
 * @date 2020/2/1
 * <p>
 * RedisTemplate  配置
 */
@Slf4j
@EnableCaching
@Configuration
public class RedisTemplateConfig {
	
	@Value("${spring.data.redis.timeout:3600}")
	private long timeout;

//    @Bean
//    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
//        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//        redisTemplate.setConnectionFactory(redisConnectionFactory);
//        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//        // key采用 String的序列化方式
//        redisTemplate.setKeySerializer(stringRedisSerializer);
//        // hash的 key也采用 String的序列化方式
//        redisTemplate.setHashKeySerializer(stringRedisSerializer);
//        // value序列化方式采用 jdk
//        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
//        // hash的 value序列化方式采用 jdk
//        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
//        redisTemplate.afterPropertiesSet();
//        return redisTemplate;
//    }
	
	/**
	 * StringRedisTemplate键值序列化
     * @author deer
     * @date 2025年4月18日
     * @param connectionFactory
     * @return
     */
	@Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(factory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        stringRedisTemplate.setKeySerializer(stringRedisSerializer);
        // hash的 key也采用 String的序列化方式
        stringRedisTemplate.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用 jdk
        stringRedisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        // hash的 value序列化方式采用 jdk
        stringRedisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        return stringRedisTemplate;
    }
	
	/**
	 * SpringCache 缓存配置
     * @author deer
     * @date 2025年4月18日
     * @param connectionFactory
     * @return
     */
	@Bean
	public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
		// redis缓存配置
		RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
				.entryTtl(Duration.ofMinutes(timeout))
				.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
				.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()))
				.disableCachingNullValues();
		// 缓存配置map
		Map<String, RedisCacheConfiguration> cacheConfigurationMap = new HashMap<>();
		// 根据redis缓存配置和redis连接工厂生成redis缓存管理器
		RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(config)
				.transactionAware().withInitialCacheConfigurations(cacheConfigurationMap).build();
		return redisCacheManager;
	}
    
    /**
	 * 缓存异常处理
	 * 用于当redis连接不上时被缓存注解标注的方法绕过Redis直连数据库
	 * @author deer
	 * @date 2025年4月18日
	 * @return
	 */
	@Bean
	public CacheErrorHandler errorHandler() {
		CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
			@Override
			public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
				log.error("redis异常：key=[{}]", key, exception);
			}
			@Override
			public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
				log.error("redis异常：key=[{}]", key, exception);
			}
			@Override
			public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
				log.error("redis异常：key=[{}]", key, exception);
			}
			@Override
			public void handleCacheClearError(RuntimeException exception, Cache cache) {
				log.error("redis异常：", exception);
			}
		};
		return cacheErrorHandler;
	}
    
}
